# -*- coding: utf8 -*-
########################################################################
# Copyright (c) 2008 Burdakov Daniel <kreved@kreved.org>               #
#                                                                      #
# This file is part of PyWoW.                                          #
#                                                                      #
# PyWoW is free software: you can redistribute it and/or modify        #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or    #
# (at your option) any later version.                                  #
#                                                                      #
# PyWoW is distributed in the hope that it will be useful,             #
# but WITHOUT ANY WARRANTY; without even the implied warranty of       #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the        #
# GNU General Public License for more details.                         #
#                                                                      #
# You should have received a copy of the GNU General Public License    #
# along with PyWoW.     If not, see <http://www.gnu.org/licenses/>.    #
########################################################################

from twisted.internet.protocol import ClientFactory
from worldpacketprotocol import WorldPacketProtocol
from constants import *
from opcodes import opcodes
import SRP
from struct import pack, unpack, calcsize
import packets

class WorldClientProtocol(WorldPacketProtocol):
 host_opcode_fmt = '<L'
 peer_opcode_fmt = '<H'
 def connectionMade(self):
  WorldPacketProtocol.connectionMade(self)
  self.status = NOTHING
 def packetReceived(self, opcode, body):
  if opcode == opcodes.SMSG_AUTH_CHALLENGE:
   sseed = body
   cseed = SRP.random_string(4)
   K = self.factory.K
   digest = self.calcAuthDigest(self.factory.username, sseed, cseed, K)
   addons = packets.CAddonList()
   addons.list = self.factory.getAddonList()
   msg = pack("<LL", self.factory.build, 0) + self.factory.username + '\x00' + cseed + digest + addons.pack()
   self.send(opcodes.CMSG_AUTH_SESSION, msg)
   self.status = SENT_PROOF
   #тут возникает парадокс...
   #если пользователь успешно авторизовался, то следующий пакет
   #SMSG_AUTH_RESPONSE придёт уже зашифрованным..
   #а если авторизация не прошла, то ответ будет не зашифрованным...
   #и теперь неизвестно, активировать ли шифрование.
   #Будем считать, что авторизация прошла успешно и включим шифрование
   #(если нет - то вскоре мы расшифруем _незашифрованный_ пакет, получим белиберду типа
   #length = 49624, opcode = 0xece5, и тупо зависнем, ожидая получения 49624 байт.)
   self.crypt.setKey(K)
   self.crypt.enable()
  elif opcode == opcodes.SMSG_ADDON_INFO:
   pass
  elif opcode == opcodes.SMSG_AUTH_RESPONSE:
   #тут такой момент... если мы смогли расшифровать заголовок пакета SMSG_AUTH_RESPONSE
   #значит на стороне сервера шифрование уже включено => авторизация прошла успешно...
   #но на всякий случай всё же проверим
   result, _, _, _, tbc = unpack("<BLBLB", body)
   if result == AUTH_OK:
    self.status = AUTHENTICATED
    self.factory.authDone(self, tbc)
   else: self.transport.loseConnection()
  else:
   self.handlePacket(opcode, body)

class WorldClientFactory(ClientFactory):
 protocol = WorldClientProtocol
 build = 8606
 def setAuthData(self, username, K):
  self.username, self.K = username, K
 def getAddonList(self):
  standart_crc = 0x1c776d01L
  addons = map(lambda x: (x, standart_crc), ['Blizzard_AuctionUI', 'Blizzard_BattlefieldMinimap', 'Blizzard_BindingUI', \
    'Blizzard_CombatLog', 'Blizzard_CombatText', 'Blizzard_CraftUI', 'Blizzard_GMSurveyUI', \
    'Blizzard_GuildBankUI', 'Blizzard_InspectUI', 'Blizzard_ItemSocketingUI', \
    'Blizzard_MacroUI', 'Blizzard_RaidUI', 'Blizzard_TalentUI', 'Blizzard_TradeSkillUI', \
    'Blizzard_TrainerUI', 'Blizzard_TimeManager'])
  return addons
 def authDone(self, session, tbc):
  """It will be called by protocol when authentication sequence done,"""
  pass
 def handlePacket(self, session, opcode, body):
  pass
